package com.zkq.lvse.common.dao.impl;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.zkq.lvse.common.dao.SimpleDao;
import com.zkq.lvse.common.utils.ReflectionUtils;

/**
 * 
 * @author zkq
 *
 * @param <T>
 * @param <PK>
 */
@SuppressWarnings("unchecked")
@Repository
public class SimpleDaoImpl<T,PK extends Serializable> implements SimpleDao<T, PK> {
	
	protected SessionFactory sessionFactory;
	protected Class<T> entityClass;
	
	public SimpleDaoImpl(){
		this.entityClass=ReflectionUtils.getSuperClass(getClass());
	}
	
	public SimpleDaoImpl(final SessionFactory sessionFactory,final Class<T> entityClass){
		this.sessionFactory=sessionFactory;
		this.entityClass=entityClass;
	}
	

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
	public Session getSession(){
		return sessionFactory.getCurrentSession();
	}
	
	/**
	 * 根据SQL创建SQLQuery对象
	 * @param hql
	 * @param values	数量可变参数，按顺序绑定
	 * @return
	 */
	public SQLQuery createSqlQuery(String sql, Object... values) {
		SQLQuery q=getSession().createSQLQuery(sql);
		if(values!=null){
			for(int i=0;i<values.length;i++){
				q.setParameter(i, values[i]);
			}
		}
		return q;
	}
	/**
	 * 根据SQL创建SQLQuery对象
	 * @param hql
	 * @param values	数量可变参数，按名称绑定
	 * @return
	 */
	public SQLQuery createSqlQuery(String sql, Map<String, ?> values) {
		SQLQuery q=getSession().createSQLQuery(sql);
		if(values!=null){
			q.setProperties(values);
		}
		return q;
	}
	/**
	 * 根据HQL和查询参数列表创建Query
	 * @param hql
	 * @param values	数量可变参数，按顺序绑定
	 * @return
	 */
	public Query createQuery(String hql,Object... values){
		Query query=getSession().createQuery(hql);
		if(values!=null){
			for(int i=0;i<values.length;i++){
				query.setParameter(i, values[i]);
			}
		}
		return query;
	}
	/**
	 * 根据HQL和查询参数列表创建Query
	 * @param hql
	 * @param values	数量可变参数，按名称绑定
	 * @return
	 */
	public Query createQuery(String hql, Map<String, ?> values) {
		Query query=getSession().createQuery(hql);
		if(values!=null){
			query.setProperties(values);
		}
		return query;
	}
	/**
	 * 执行HQL进行批量修改/删除
	 * @param hql
	 * @param values	数量可变参数，按顺序绑定
	 */
	public int delAll(String hql, Object... values) {
		return createQuery(hql, values).executeUpdate();
	}
	/**
	 * 执行HQL进行批量修改/删除
	 * @param hql
	 * @param values	数量可变参数，按名称绑定
	 */
	public int delAll(String hql, Map<String, ?> values) {
		return createQuery(hql, values).executeUpdate();
	}
	/**
	 * 根据id删除一条数据
	 * @param id
	 */
	public void delete(PK id) {
		getSession().delete(get(id));
	}
	/**
	 * 根据实体类删除一条数据
	 * @param entity
	 */
	public void delete(T entity) {
		getSession().delete(entity);
	}
	/**
	 * 根据Id查询实体对象
	 * @param id
	 * @return
	 */
	public T get(PK id) {
		return (T)getSession().get(entityClass,id);
	}
	/**
	 * 添加数据
	 * @param entity
	 */
	public void save(T entity) {
		getSession().save(entity);
	}
	/**
	 * 添加或修改数据
	 * @param entity
	 */
	public void saveOrUpdate(T entity) {
		getSession().saveOrUpdate(entity);
	}
	/**
	 * 修改数据
	 * @param entity
	 */
	public void update(T entity) {
		getSession().update(entity);
	}
	/**
	 * 查询对象列表
	 * @param hql
	 * @param values	数量可变参数，按顺序绑定
	 * @return
	 */
	public List<T> find(String hql, Object... values) {
		return createQuery(hql, values).list();
	}
	/**
	 * 查询对象列表
	 * @param hql
	 * @param values	数量可变参数，按名称绑定
	 * @return
	 */
	public List<T> find(String hql, Map<String, ?> values) {
		return createQuery(hql, values).list();
	}
	/**
	 * 根据Id列表获取对象列表
	 * @param ids
	 * @return
	 */
	public List<T> find(Collection<PK> ids) {
		return find(Restrictions.in(getIdName(), ids));
	}
	/**
	 * 根据Criteria查询对象列表
	 * @param criteria
	 * @return
	 */
	public List<T> find(Criterion... criterions) {
		return createCriteria(criterions).list();
	}
	/**
	 * 根据criterion创建Criteria对象
	 * @param criterions
	 * @return
	 */
	public Criteria createCriteria(final Criterion... criterions){
		Criteria criteria=getSession().createCriteria(entityClass);
		for(Criterion c:criterions){
			criteria.add(c);
		}
		return criteria;
	}
	/**
	 * 根据criterion创建Criteria对象并排序
	 * @param criterions
	 * @return
	 */
	public Criteria createCriteria(final String order,final Criterion... criterions){
		Criteria criteria=getSession().createCriteria(entityClass);
		for(Criterion c:criterions){
			criteria.add(c);
		}
		criteria.addOrder(Order.desc(order));
		return criteria;
	}
	
	/**
	 * 取得对象的主键名
	 */
	public String getIdName(){
		ClassMetadata meta=getSessionFactory().getClassMetadata(entityClass);
		return meta.getIdentifierPropertyName();
	}
	/**
	 * 根据Id列表获取对象列表并排序
	 * @param ids
	 * @return
	 */
	public List<T> find(String order, Collection<PK> ids) {
		return find(order,Restrictions.in(getIdName(), ids));
	}
	/**
	 * 根据Criteria查询对象列表并排序
	 * @param criteria
	 * @return
	 */
	public List<T> find(String order, Criterion criterions) {
		return createCriteria(order, criterions).list();
	}
	/**
	 * 根据属性查找对象列表
	 * @param propertyName
	 * @param value
	 * @return
	 */
	public List<T> findBy(String propertyName, Object value) {
		Criterion c=Restrictions.eq(propertyName, value);
		return createCriteria(c).list();
	}

	/**
	 * 根据属性查找唯一对象
	 * @param propertyName
	 * @param value
	 * @return
	 */
	public T findUnique(String propertyName, Object value) {
		Criterion c=Restrictions.eq(propertyName, value);
		return findUnique(c);
	}
	/**
	 * 根据Criterion查找唯一对象
	 * @param propertyName
	 * @param value
	 * @return
	 */
	public T findUnique(Criterion... criterions) {
		return (T) createCriteria(criterions).uniqueResult();
	}

	public List<T> findAll(String sql, Class<T> entity) {
		SQLQuery c=createSqlQuery(sql).addEntity(entity);
		return c.list();
	}

	public List<T> getAll() {
		return find();
	}
}
